module complement_vector(/*AUTOARG*/
   // Outputs
   o_comp,
   // Inputs
   i_a, i_gen, i_mode
   );

   parameter width = 64;		// total width
   parameter granu = 8;			// granularity(8/16/32/64)
   localparam fields_num = width / granu;
   localparam mode_num = log2(fields_num) + 1; // the num of mode
   
   output logic [width-1:0] o_comp;
   input logic [fields_num-1:0][granu-1:0] i_a;
   input logic [fields_num-1:0] 		   i_gen; // gen 2's complement or not
   input logic [mode_num-1:0] 			   i_mode;
   
   
   logic [fields_num-1:0][granu-1:0] 	   inv_mask, inv_const;
   always_comb
	 begin
		logic inv_flag;
		for(int i=0;i<fields_num;i++)
		  begin
			 inv_flag = 1'b0;
			 inv_const[i] = '0;
			 for(int j=0;j<mode_num;j++)
			   begin
				  if(i%(2**j) == 0)
				  	inv_const[i] |= i_mode[j] & i_gen[i+2**j-1];
				  
				  inv_flag |= i_mode[j] & i_gen[(i/(2**j)+1)*(2**j)-1];
			   end
			 inv_mask[i] = {granu{inv_flag}};
		  end
	 end // always_comb

   logic [width-1:0] sum;
   add_vector #(.width(width),
				.granu(granu)) U_add_vector(
											// Outputs
											.o_sum				(sum),
											.o_carrys			(),
											// Inputs
											.i_a				(i_a ^ inv_mask), //2's complement: ~a+1
											.i_b				(inv_const),
											.i_mode				(i_mode) );
   
   assign o_comp = sum;

endmodule
